package com.tarzan.redis.service.impl;

import com.tarzan.common.core.utils.JSONUtil;
import com.tarzan.redis.service.RedisService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * @author liujinshan
 * @title: RedisServiceImpl
 * @projectName tarzan-cloud
 * @description: TODO  redis 公共接口
 * @date 2021-5-17 21:42
 */
@Service
public class RedisServiceImpl implements RedisService {

    @Autowired
    private RedisTemplate<String, ?> redisTemplate;


    /**
     * 缓存值并设定时效
     *
     * @param key   键
     * @param value 值
     * @param time
     * @return boolean
     */
    @Override
    public boolean set(String key, String value, long time) {
        return redisTemplate.execute((RedisConnection connection) -> {
            RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
            connection.set(serializer.serialize(key), serializer.serialize(value));
            if (time > 0) {
                expire(key, time);
            }
            return true;
        });
    }


    /**
     * 缓存值为对象 并且设置缓存 时效 以及缓存 时效单位
     *
     * @param key      key
     * @param value    对象值
     * @param timeout  失效时间
     * @param timeUnit 单位
     * @return
     */
    @Override
    public <T> ValueOperations<String, T> setObject(String key, T value, Integer timeout, TimeUnit timeUnit) {
        ValueOperations<String, T> operation = (ValueOperations<String, T>) redisTemplate.opsForValue();
        operation.set(key, value, timeout, timeUnit);
        return operation;
    }

    /**
     * 获得缓存的基本对象。
     *
     * @param key 缓存键值
     * @return 缓存键值对应的数据
     */
    @Override
    public <T> T getObject(String key) {
        ValueOperations<String, T> operation = (ValueOperations<String, T>) redisTemplate.opsForValue();
        return operation.get(key);
    }

    protected boolean expire(final String key, long expire) {
        return redisTemplate.expire(key, expire, TimeUnit.SECONDS);
    }

    /**
     * 缓存值
     *
     * @param key   键
     * @param value 值
     * @return boolean
     */
    @Override
    public boolean set(String key, String value) {
        return redisTemplate.execute((RedisConnection connection) -> {
            RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
            connection.set(serializer.serialize(key), serializer.serialize(value));
            return true;
        });
    }


    /**
     * 删除值
     *
     * @param key 键
     * @return boolean
     */
    @Override
    public boolean del(String key) {
        return redisTemplate.execute((RedisConnection connection) -> {
            RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
            connection.del(serializer.serialize(key));
            return true;
        });
    }

    /**
     * 根据key获取缓存中的值
     *
     * @param key 键
     * @return String
     */
    @Override
    public String get(String key) {
        return redisTemplate.execute((RedisConnection connection) -> {
            RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
            byte[] value =  connection.get(serializer.serialize(key));
            return serializer.deserialize(value);
        });
    }

    /**
     * 缓存list
     *
     * @param key  键
     * @param list list
     * @return boolean
     */
    @Override
    public <T> boolean setList(String key, List<T> list) {
        String value = JSONUtil.toJson(list);
        return set(key,value);
    }

    /**
     * 根据key获取缓存中的list
     *
     * @param key 键
     * @param clz class
     * @return List<T>
     */
    @Override
    public <T> List<T> getList(String key, Class<T> clz) {
        String json = get(key);
        if(!json.isEmpty()){
            List<T> list = JSONUtil.toList(json, clz);
            return list;
        }
        return null;
    }

    /**
     * 在key对应list的头部添加字符串元素
     *
     * @param key 键
     * @param obj 对象
     * @return long
     */
    @Override
    public long lpush(String key, Object obj) {
        final String value = JSONUtil.toJson(obj);
        return redisTemplate.execute((RedisConnection connection) -> {
            RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
            long count = connection.lPush(serializer.serialize(key), serializer.serialize(value));
            return count;
        });
    }

    /**
     * 在key对应list的尾部添加字符串元素
     *
     * @param key 键
     * @param obj 对象
     * @return long
     */
    @Override
    public long rpush(String key, Object obj) {
        final String value = JSONUtil.toJson(obj);
        return redisTemplate.execute((RedisConnection connection) -> {
            RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
            long count = connection.rPush(serializer.serialize(key), serializer.serialize(value));
            return count;
        });
    }

    /**
     * 在key对应list上移除并返回list的最后一个元素
     *
     * @param key 键
     * @return String
     */
    @Override
    public String lpop(String key) {
        return redisTemplate.execute((RedisConnection connection) -> {
            RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
            byte[] res =  connection.lPop(serializer.serialize(key));
            return serializer.deserialize(res);
        });
    }

    /**
     * 哈希添加
     *
     * @param key     键 键
     * @param hashKey 哈希键
     * @param value   值 值
     */
    @Override
    public void hSet(String key, Object hashKey, Object value) {
        HashOperations<String, Object, Object> hash = this.redisTemplate.opsForHash();
        hash.put(key, hashKey, value);
    }

    /**
     * 哈希添加
     *
     * @param key    键 键
     * @param values 值
     */
    @Override
    public void hSetAll(String key, Map<?, ?> values) {
        HashOperations<String, Object, Object> hash = this.redisTemplate.opsForHash();
        hash.putAll(key,values);
    }

    /**
     * 获取哈希
     *
     * @param key     键 主键
     * @param hashKey 哈希键
     * @return obj
     */
    @Override
    public Object hGet(String key, Object hashKey) {
        HashOperations<String, Object, Object> hash = this.redisTemplate.opsForHash();
        return hash.get(key, hashKey);
    }

    /**
     * 获取所有哈希键
     *
     * @param key 键 主键
     * @return keys
     */
    @Override
    public Set<Object> hKeys(String key) {
        HashOperations<String, Object, Object> hash = this.redisTemplate.opsForHash();
        return hash.keys(key);
    }

    /**
     * 删除哈希键
     *
     * @param masterKey 主键
     * @param hashKey   哈希键
     */
    @Override
    public void hDel(String masterKey, Object... hashKey) {
        HashOperations<String, Object, Object> hash = this.redisTemplate.opsForHash();
        hash.delete(masterKey, hashKey);
    }
}
